package com.glsc.ngateway.oaflow.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.glsc.ngateway.common.api.shortmsg.bo.WebhookGenericVo;
import com.glsc.ngateway.common.api.shortmsg.feign.IFeignShortmsgService;
import com.glsc.ngateway.common.base.domain.mysql.gateway.other.EmailClient;
import com.glsc.ngateway.common.base.domain.mysql.gateway.other.SystemConfig;
import com.glsc.ngateway.common.base.repo.mysql.gateway.other.EmailClientRepository;
import com.glsc.ngateway.common.base.repo.mysql.gateway.other.SystemConfigRepository;
import com.glsc.ngateway.oaflow.exception.GatewayException;
import com.glsc.ngateway.oaflow.utils.Constant;
import com.glsc.ngateway.oaflow.utils.DictConstant;
import com.glsc.ngateway.oaflow.utils.SpringUtil;
import lombok.SneakyThrows;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.mail.MailProperties;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.mail.Address;
import javax.mail.MessagingException;
import javax.mail.SendFailedException;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
import java.io.*;
import java.text.MessageFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.glsc.ngateway.oaflow.utils.DictConstant.MAIL_SERVICE_OAFLOW;
import static com.glsc.ngateway.oaflow.utils.DictConstant.MAIL_STATUS_NOT_SEND_ID;

/**
 * @author zhouzp
 * @date 2020/6/17
 * 邮件发送服务
 */
@Service
public class MailService {

    private static Logger logger = LoggerFactory.getLogger(MailService.class);

    @Resource(name = "mailSender")
    private JavaMailSender mailSender;

    @Resource
    private IFeignShortmsgService shortmsgService;

    @Resource
    private SystemConfigRepository systemConfigRepository;

    @Autowired
    private EmailClientRepository emailClientRepository;

    public static final String TEST_MAIL_TITLE_PREFIX = "【系统测试邮件】";

    private String senderEmail = "itmanagesys@glsc.com.cn";

    public MailService(MailProperties mailProperties) {
        this.senderEmail = mailProperties.getUsername();
    }

    public String getSenderEmail() {
        return senderEmail;
    }

    public void setSenderEmail(String senderEmail) {
        this.senderEmail = senderEmail;
    }
    /**
     * 获取发件人别称地址：别名<邮件地址>
     *
     * @return 返回带别称的邮件地址，如  资管产品管理系统<itmanagesys@glsc.com.cn>
     */
    public String getSenderEmailWithName() {
        String sender = "国联技术服务平台<" + senderEmail + ">";//发件人别名必须是：别名<邮件地址>格式

        return sender;
    }


    /**
     * 发送邮件
     *
     * @param recvMailList   邮件接收人邮箱列表
     * @param title          邮件标题
     * @param content        邮件内容
     * @param attachmentList 附件列表
     * @throws GatewayException
     */
    public String sendMail(List<String> recvMailList, String recipientNames, String title, String content, List<File> attachmentList) {
        if (CollectionUtils.isEmpty(recvMailList)) {
            logger.error("发送邮件时，收件人为空");
            return "";
        } else {
            return this.sendMail(recvMailList.toArray(new String[recvMailList.size()]), recipientNames, title, content, attachmentList);
        }
    }

    /**
     * 发送邮件
     *
     * @param recipientEmailArray 邮件接收人邮箱列表
     * @param recipientNames 邮件接收人名称，用于收件人称呼，如"张三，您好“，允许为空
     * @param title 邮件标题
     * @param content 邮件内容
     * @param attachmentList 附件列表，允许为空
     * @throws GatewayException
     */
//    @Transactional
    public String sendMail(String[] recipientEmailArray,String recipientNames, String title,String content,List<File> attachmentList) {
        if(null==recipientEmailArray||recipientEmailArray.length==0){
            throw GatewayException.error("接收人邮箱不能为空：");
        }
        String notSendRecvList = null;
//        String notSendRecvList = systemConfigService.findConfigValueByCode(Constant.CONFIG_KEY_NOT_SEND_RECV_LIST);
        List<String> recvMailList = Arrays.stream(recipientEmailArray).filter(item->notSendRecvList == null || !notSendRecvList.contains(item)).distinct().collect(Collectors.toList());
        if(CollectionUtils.isEmpty(recvMailList)){
            logger.error("发送邮件时，收件人为空");
            return "";
        }

        recipientEmailArray = recvMailList.toArray(new String[recvMailList.size()]);
        String recipientEmailStr = StringUtils.join(recipientEmailArray, ",");
        InternetAddress[] recipientEmails = null;
        try {
            recipientEmails = InternetAddress.parse(recipientEmailStr);
        } catch (AddressException e) {
            logger.error("发送邮件时，收件人邮箱不合法：" + recipientEmailStr);
            throw GatewayException.error("收件人邮箱不合法：" + recipientEmailStr);
        }

        //邮件标题
        if (StringUtils.isEmpty(title) || StringUtils.isEmpty(content)) {
            throw GatewayException.error("发送邮件标题或内容不能为空，标题为" + title + "，邮件内容为" + content);
        }


        if (SpringUtil.isTestingByActiveProfile()) {//测试环境，强制增加测试标题
            title = TEST_MAIL_TITLE_PREFIX + title;
        }

        String mailId = "";
        MimeMessage mailMessage = null;
        MimeMessageHelper mailHelper=null;
//        EmailClient emailClient = new EmailClient();
        try {
            mailMessage = mailSender.createMimeMessage();
            mailHelper = new MimeMessageHelper(mailMessage, true, "utf-8");
            logger.info("邮件服务初始化成功");
            String sender = this.getSenderEmailWithName();
            String recipient = recipientEmailStr;
            String randomStr = UUID.randomUUID().toString();

            //设置邮件内容*****************************************************************
            //绿色
            String emailHeadColor = "#10fa81";

            String helloNameStr = null;
            if (StringUtils.isEmpty(recipientNames)) {/*动态支持："你好"或者有收件人姓名的"张三，你好"*/
                helloNameStr = "";/*如果设置为null，则会出现null文本在邮件中，因此这里设置为空字符串*/
            } else {
                helloNameStr = StringUtils.trim(recipientNames) + "，";
            }
            String mailTemplate = getMailTemPlate(Constant.MAIL_TYPE_COMMON);

            String currentTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");

            //填充html模板中的参数
            String htmlText = MessageFormat.format(mailTemplate, emailHeadColor, title, helloNameStr, content, currentTime);


            //保存文件内容需要保存文件路径列表和文件名称列表供重新发送使用
            buildAttachmentList(attachmentList, mailHelper);

            //存储邮件发送信息到t_am_email_client表中
            mailId = "";
            mailId = saveEmailClient(DictConstant.MAIL_TYPE_MAIL_DEFAULT, sender, recipient, title, htmlText, randomStr, null, null);
            //End of 设置设置邮件内容*****************************************************

            mailHelper.setText(htmlText, true);//邮件内容


            //发送邮件，更新邮件状态为成功。
            mailHelper.setFrom(sender);
            mailHelper.setTo(recipientEmailArray);
            mailHelper.setSubject(title);

            if (!MAIL_STATUS_NOT_SEND_ID.equals(mailId)){
                mailSender.send(mailMessage);
            }
//            emailClientRepository.updateStatusByMailId(mailId, DictConstant.MAIL_STATUS_SUCCESS,"");

        } catch (SendFailedException e) {
            //进入这个异常就代表 出现了 某些 邮箱地址 是错误的情况  可能有人离职 邮箱 注销了
            logger.warn("存在邮箱无法发送,过滤异常邮箱再次发送,当前收件人清单:{},.", (Object[]) recipientEmailArray);

            try {//获取 正确的地址，再次尝试发送一次
                Address[] validAddressArray = e.getValidUnsentAddresses();
                String[] successEmailArray = null;
                if (validAddressArray != null && validAddressArray.length > 0) {
                    successEmailArray = new String[validAddressArray.length];
                    for (int k = 0; k < validAddressArray.length; k++) {
                        successEmailArray[k] = validAddressArray[k].toString();
                    }

                    logger.warn("存在邮箱无法发送,过滤异常邮箱再次发送,当前收件人清单：{},过滤后仅剩正确的收件人清单：{}"
                            , recipientEmailArray, successEmailArray);
                    mailHelper.setTo(successEmailArray);
                    mailSender.send(mailMessage);
                    String moreRemark = "存在异常邮箱，之前收件人：" + String.join(",", recipientEmailArray)
                            + ",过滤之后合法邮箱：" + String.join(",", successEmailArray);
//                    emailClientRepository.updateStatusByMailId(mailId, DictConstant.MAIL_STATUS_SUCCESS, moreRemark);
                } else {
//                    logger.error("收件邮箱：{}， 邮件标题： {}， 邮件内容：{}", emailClient.getRecipient(), emailClient.getTitle(), emailClient.getContent());
                    this.remindFailSendMail(mailId, e.getMessage());
                }
            } catch (Exception ex) {
//                logger.error("收件邮箱：{}， 邮件标题： {}， 邮件内容：{}", emailClient.getRecipient(), emailClient.getTitle(), emailClient.getContent());
                this.remindFailSendMail(mailId, ex.getMessage());
            }
        } catch (Exception ex) {
//            logger.error("收件邮箱：{}， 邮件标题： {}， 邮件内容：{}", emailClient.getRecipient(), emailClient.getTitle(), emailClient.getContent());
            this.remindFailSendMail(mailId, ex.getMessage());
        }
        return mailId;
    }

    /**
     * 邮件发送失败给管理员发送提醒
     */
    private void remindFailSendMail(String mailId, String failMessage) {
        if (StringUtils.isEmpty(mailId)) {
            return;
        }

        logger.error("邮件发送异常，邮件id为{},原因：{}", mailId, failMessage);

        //更新邮件发送失败状态及原因。
        String failReason = DateUtil.format(new Date(), "yyyy-MM-dd hh:mm:ss SSS") + "###" + failMessage;
        failReason = failReason.length() > 500 ? failReason.substring(0, 500) : failReason;

//        emailClientRepository.updateFailReasonByMailId(mailId, failReason);
//
//        //邮件发送失败，给管理员发送短信提醒
//        messageSender.sendShortMessageToAdmin("邮件发送异常,请登录系统查看");
        //向管理员报告邮件发送失败
        this.sendMailToAdmin(Constant.MAIL_TITLE_SEND_FAILURE, "邮件发送编码为: " + mailId + "的邮件发送失败，请检查！");
    }

    /**
     * 保存邮件内容单独出来可以复用
     * @param mailType
     * @param sender
     * @param recipient
     * @param title
     * @param htmlText
     * @param randomStr
     * @param fileNameList
     * @param filePathList
     * @return
     */
    private String saveEmailClient(String mailType,String sender,String recipient,String title,String htmlText,String randomStr,String fileNameList,String filePathList){
        Boolean sameContent = hasSameContent(htmlText,MAIL_SERVICE_OAFLOW);
        EmailClient ec = new EmailClient();
        ec.setMailType(mailType);
        ec.setSender(sender);
        ec.setRecipient(recipient);
        ec.setTitle(title);
        ec.setContent(htmlText);
        ec.setRandomStr(randomStr);
        ec.setStatus(DictConstant.MAIL_STATUS_TODO);
        ec.setFileNameList(fileNameList);
        ec.setFilePathList(filePathList);
        ec.setServiceName(MAIL_SERVICE_OAFLOW);
        if (sameContent){
            ec.setStatus(DictConstant.MAIL_STATUS_NO);
        }
        String mailId = emailClientRepository.save(ec).getMailId() + "";
        if (sameContent){
            return MAIL_STATUS_NOT_SEND_ID;
        }
        return mailId;
    }

    /**
     * 处理邮件附件单独出来可以复用
     * @param attachmentList
     * @param helper
     * @throws MessagingException
     */
    private void buildAttachmentList(List<File> attachmentList, MimeMessageHelper helper) throws MessagingException, UnsupportedEncodingException {
        //保存文件内容需要保存文件路径列表和文件名称列表供重新发送使用
        StringBuilder filePathListApp = new StringBuilder("");
        StringBuilder fileNameListApp = new StringBuilder("");
        String fileNameList = null;
        String filePathList = null;
        if (!CollectionUtils.isEmpty(attachmentList)) {//附件不为空
            for (File attachment : attachmentList) {
                helper.addAttachment(MimeUtility.encodeWord(attachment.getName(),"UTF-8","B"), attachment);
                filePathListApp.append(attachment.getAbsolutePath()).append(",");
                fileNameListApp.append(attachment.getName()).append(",");
            }
            filePathList = filePathListApp.toString();
            fileNameList = fileNameListApp.toString();
            filePathList = filePathList.substring(0,filePathList.length() - 1);
            fileNameList = fileNameList.substring(0,fileNameList.length() - 1);
//            ec.setFilePathList(filePathList);
//            ec.setFileNameList(fileNameList);
        }
    }

    /*检查发件信息是否合法*/
    protected void checkEmailValid(String sender, String recipient, String title) {
        if (sender == null || sender.isEmpty()) {
            throw GatewayException.error("发件人不能为空");
        }
        if (recipient == null || recipient.isEmpty()) {
            throw GatewayException.error("收件人不能为空");
        }
        if (title == null || title.isEmpty()) {
            throw GatewayException.error("邮件标题不能为空");
        }
    }

    /**
     * 根据邮件模板类型获取模板内容
     * @pram type 邮件模板类型
     * */

    private String getMailTemPlate(String type) throws Exception {
        //加载邮件html模板
        String fileName = "";
        if (Constant.MAIL_TYPE_RESPONSIBLE_CONFIRM.equals(type)) {
            fileName = Constant.TEMPLATE_NAME_CONFIRM_INFO;
        } else if (Constant.MAIL_TYPE_ELIG_AUDIT.equals(type)) {
            fileName = Constant.TEMPLATE_NAME_ELIG_CHECK;
        } else if (Constant.MAIL_TYPE_EXPIRE_REMIND.equals(type)) {
            fileName = Constant.TEMPLATE_NAME_EXPIRE_REMIND;
        } else if (Constant.MAIL_TYPE_AUDIT_REJECT.equals(type)) {
            fileName = Constant.TEMPLATE_NAME_AUDIT_REJECT;
        } else if (Constant.MAIL_TYPE_ACCOUNT_OPEN.equals(type)) {
            fileName = Constant.TEMPLATE_NAME_ACCOUNTTYPE_OPEN;
        } else if (Constant.MAIL_TYPE_COMMON.equals(type)) {
            fileName = Constant.TEMPLATE_NAME_TYPE_COMMON;
        } else if (Constant.MAIL_TYPE_REPORT.equals(type)) {
            fileName = Constant.TEMPLATE_NAME_TYPE_REPORT;
        } else if (Constant.MAIL_TYPE_REMIND_FEE_CARRY.equals(type)) {
            fileName = Constant.TEMPLATE_NAME_TYPE_REMIND_FEE_CARRY;
        } else if (Constant.MAIL_TYPE_CUSTODIAN.equals(type)) {
            fileName = Constant.TEMPLATE_NAME_TYPE_CUSTODIAN;
        } else {
            throw GatewayException.error("未找到邮件模板");
        }

        InputStream inputStream = MailService.class.getClassLoader().getResourceAsStream(fileName);
        BufferedReader fileReader = new BufferedReader(new InputStreamReader(inputStream));

        StringBuffer buffer = new StringBuffer();
        String line = null;

        try {
            while ((line = fileReader.readLine()) != null) {
                buffer.append(line);
            }
        } catch (Exception e) {
            logger.error("读取邮件模板文件" + fileName + "时发生异常!", e);
        } finally {
            inputStream.close();
            fileReader.close();
        }

        return buffer.toString();
    }


    /**
     * 向管理员发送邮件提醒
     */
    @SneakyThrows
    public void sendMailToAdmin(String title, String content) {
        try {
            if (SpringUtil.isTestingByActiveProfile()) {
                title = TEST_MAIL_TITLE_PREFIX + title;
            }

            MimeMessage message = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            String sender = this.getSenderEmailWithName();

            String recipientStr = "weizt@glsc.com.cn,itmanagesys@glsc.com.cn";
            SystemConfig config = systemConfigRepository.findByConfigCode(DictConstant.OAFLOW_ADMIN_MAIL);
            if (config != null && StringUtils.isNotEmpty(config.getConfigValue())){
                recipientStr = config.getConfigValue();
            }

            recipientStr = recipientStr.replace("，", ",");
            String[] recipientStrArray = recipientStr.split(",");
            String mailId = "";
            mailId = saveEmailClient(DictConstant.MAIL_TYPE_MAIL_DEFAULT, sender, recipientStr, title, content, null, null, null);
//            logger.info("保存发送邮件成功：mailId=" + mailId);

            helper.setFrom(sender);
            helper.setTo(recipientStrArray);//一次性可以发送多个
            helper.setSubject(title);
            helper.setText(content, true);//邮件内容

            if (SpringUtil.isTestingByActiveProfile()) {
                logger.error("开发测试环境，邮件发送异常，不再发送短信，因为测试环境无短信测试环境，短信发送会失败");
            } else {//生产环境，才真正发送短信
                //5分钟内重复内容的邮件不发

                if (!MAIL_STATUS_NOT_SEND_ID.equals(mailId)){
                    mailSender.send(message);
                    //发送企业微信
                    try {
                        sendQywx("OAFlow异常"+content);
                    } catch (Exception e){
                        logger.error(e.getMessage());
                    }
                }

            }
//            emailClientRepository.updateStatusByMailId(mailId, DictConstant.MAIL_STATUS_SUCCESS, "");
        } catch (Exception ex) {
            logger.error("向管理员发送邮件异常message：" + ex.getLocalizedMessage(), ex);
            logger.error("邮件标题： " + title + "， 邮件内容：" + content + "");
            throw ex;
//            messageSender.sendShortMessageToAdmin("向管理员发送邮件异常,请登录系统查看");
        }
    }

    private Boolean hasSameContent(String content, String serviceName) {
        LocalDateTime before = LocalDateTime.now().minus(Duration.ofMinutes(10));
        List<EmailClient> mailList = emailClientRepository.findAllByContentAndServiceNameAndOpTimeAfter(content,serviceName,before);
        if (CollectionUtil.isNotEmpty(mailList)){
            return true;
        }
        return false;
    }

    private void sendQywx(String content) {
        Map contentMap = new HashMap();
        contentMap.put("content",content);
        String wxgroupId = "884c9152-4c8e-4bdc-8012-66fe820de75c";
        SystemConfig config = systemConfigRepository.findByConfigCode(DictConstant.OAFLOW_WX_GROUP_ID);
        if (config != null && StringUtils.isNotEmpty(config.getConfigValue())){
            wxgroupId = config.getConfigValue();
        }
        WebhookGenericVo wx = WebhookGenericVo.builder()
                        .webhookUrl("https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key="+wxgroupId)
                        .msgType("text").build();
                        wx.addAdditionalProperty("text",contentMap);
        shortmsgService.sendGroupRobotMessage(wx);
    }

    public void sendSimpleMail(String to, String subject, String context) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(senderEmail);
        message.setTo(to);
        message.setSubject(subject);
        message.setText(context);
        mailSender.send(message);

    }
}

